#ifndef COMPLEX_H
#define COMPLEX_H

#include <stdbool.h>

typedef struct
{
	/**
	 * Real part of the complex number
	 */
	double real;

	/**
	 * Imaginary part of the complex number
	 */
	double imaginary;
} Complex;

/**
 * Creates a complex number with real part \p real and imaginary part
 * \p imaginary.
 * @param real - Real part.
 * @param imaginary - Imaginary part.
 * @return An initialized complex number.
 */
Complex complexCreate( double real, double imaginary );

/**
 * Creates an invalid complex number - a number with Real = Imaginary = NaN.
 * \note NaN is a special floating-point number that symbolizes "not a number".
 * \n Use \p NAN which is \p #define in \p math.h .
 * @return An invalid complex number: Real = Imaginary = NaN.
 */
Complex complexCreateInvalid();

/**
 * Creates a complex number z, such that |z| = \p absoluteValue and arg(z) =
 * \p argument.
 * \par Reminder:
 * Real part = \p absoluteValue * Cos( \p argument ) \n
 * Imaginary part = \p absoluteValue * Sin( \p argument ) \n
 * @param absoluteValue - Size of the complex number to be created.
 * @param argument - angle (in radians) between the real line and the number.
 * @return An initialized complex number. \n If \p absoluteValue is negative,
 * return an invalid complex number (such as the one returned by
 * complexCreateInvalid() ).
 */
Complex complexCreateFromPolar( double absoluteValue, double argument );

/**
 * Checks whether a complex number is valid - that is, if both real and
 * imaginary parts are finite (that is, not NaN or +/- INF).
 * \note Use the \p isfinite() function from math.h
 * @param complex - The number to check.
 * @return \p true if and only if both real and imaginary parts are finite.
 */
bool complexIsValid( Complex complex );

/**
 * Checks whether a complex number is zero - that is, if both real and
 * imaginary parts are 0.0.
 * @param complex - The number to check.
 * @return \p true if and only if both real and imaginary parts are 0.0.
 */
bool complexIsZero( Complex complex );

/**
 * Checks whether two complex numbers are equal - that is, if both their real
 * and imaginary parts are equal.
 * @param complex1 - The first number
 * @param complex2 - The second number
 * @return \p true if and only if both real and imaginary parts of the numbers
 * are equal.
 */
bool complexIsEqual( Complex complex1, Complex complex2 );

/**
 * Computes the additive inverse of a number.
 * \par Reminder:
 * The negation of a complex number a + i*b is -a - i*b.
 * @param complex - The number to negate.
 * @return The negation of \p complex.
 */
Complex complexNegate( Complex complex );

/**
 * Computes a sum of two complex numbers.
 * \par Reminder:
 * The sum of two complex numbers a+b*i and c+d*i is (a+c)+(b+d)*i
 * @param complex1 - The first number.
 * @param complex2 - The second number.
 * @return A complex number that equals \p complex1 + \p complex2.
 */
Complex complexAdd( Complex complex1, Complex complex2 );

/**
 * Computes complex1 - complex2.
 * \par Reminder:
 * The difference of two complex numbers a+b*i and c+d*i is (a-c)+(b-d)*i
 * @param complex1 - The first number.
 * @param complex2 - The second number.
 * @return A complex number that equals \p complex1 - \p complex2.
 */
Complex complexSubtract( Complex complex1, Complex complex2 );

/**
 * Computes complex1 * complex2.
 * \par Reminder:
 * The product of two complex numbers a+b*i and c+d*i is
 * (a*c - b*d) + (b*c + a*d)*i
 * @param complex1 - The first number.
 * @param complex2 - The second number.
 * @return A complex number that equals \p complex1 * \p complex2.
 */
Complex complexMultiply( Complex complex1, Complex complex2 );

/**
 * Computes the conjugate of a complex number
 * \par Reminder:
 * The conjuate of a complex number a+b*i is a-b*i
 * @param complex - The number to conjugate
 * @return The conjugate of \p complex.
 */
Complex complexConjugate( Complex complex );

/**
 * Returns the size (= norm, = Abs) of \p complex.
 * \par Reminder:
 * The size of a complex number a+b*i is sqrt( a*a + b*b ).
 * @param complex - The number to operate on.
 * @return The size of \p complex.
 */
double complexAbsoluteValue( Complex complex );

/**
 * Returns the argument (= angle) of \p complex.
 * \note The argument of a complex number a+b*i is atan2( b, a ).
 * \note atan2 is similar to \p ArcTan(), and essentially computes an angle
 *       given a proportion. For more information, see
 *       http://en.wikipedia.org/wiki/Atan2
 * @param complex - The number to operate on.
 * @return The argument of \p complex.
 */
double complexArgument( Complex complex );

/**
 * Computes the multiplicative inverse of \p complex.
 * \par Reminder:
 * The inverse of a complex number \p z is Conjugate(\p z) / ( Abs(\p z)^2 )
 * @param complex - The number to operate on.
 * @return The inverse of \p complex.
 */
Complex complexInverse( Complex complex );

/**
 * Computes the division of \p complex1 by \p complex2.
 * @param complex1 - The first number
 * @param complex2 - The second number
 * @return The complex number that is \p complex1 / \p complex2.
 */
Complex complexDivide( Complex complex1, Complex complex2 );

#endif /* COMPLEX_H_ */
